package com.jfs.security.utils;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.jfs.security.authentication.JwtUser;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.core.Authentication;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description JWT工具类
 * @E-mail cwm3412638@163.com
 * @Author cwm
 * @Date 2022/8/5
 */
public class JwtTokenUtils {
    /**
     * 用户名称
     */
    private static final String USERNAME = Claims.SUBJECT;
    /**
     * 创建时间
     */
    private static final String CREATED = "created";
    /**
     * 权限列表
     */
    private static final String AUTHORITIES = "authorities";

    private static final String AUTHORIZATION = "Authorization";

    private static final String TOKEN_HEAD = "Bearer ";

    public static final String ID = "id";
    public static final String ROLE_ID = "roleId";
    public static final String PHONE = "phone";
    public static final String NICK_NAME = "nickName";
    public static final String ROLE = "role";
    public static final String USER_NAME="username";
    public static final String ENABLE="enable";


    /**
     * 生成令牌
     *
     * @param authentication 用户
     * @return 令牌
     */
    public static String generateToken(Authentication authentication, long expireTime, String secret) {
        Map<String, Object> claims = new HashMap<>(16);
        Object principal = authentication.getPrincipal();
        if (principal instanceof JwtUser) {
            JwtUser jwtUser = (JwtUser) principal;
            claims.put(USERNAME, jwtUser.getUsername());
            claims.put(ID, jwtUser.getId());
            claims.put(ROLE_ID, jwtUser.getRoleId());
            claims.put(PHONE, jwtUser.getPhone());
            claims.put(NICK_NAME, jwtUser.getNickName());
            claims.put(ROLE, jwtUser.getRole());
            claims.put(ENABLE,jwtUser.getEnabled());
        } else {
            claims.put(USERNAME, authentication.getName());
        }
        claims.put(CREATED, DateUtil.date());
        claims.put(AUTHORITIES, authentication.getAuthorities());
        return generateToken(claims, expireTime, secret);
    }

    /**
     * 从数据声明生成令牌
     *
     * @param claims 数据声明
     * @return 令牌
     */
    private static String generateToken(Map<String, Object> claims, long expireTime, String secret) {
        DateTime expirationDate = DateUtil.date(System.currentTimeMillis() + expireTime);
        return Jwts.builder().setClaims(claims).setExpiration(expirationDate).signWith(SignatureAlgorithm.HS512, secret).compact();
    }

    /**
     * 获取token
     *
     * @return
     */
    public static String getTokenForRequest() {
        HttpServletRequest httpServletRequest = HttpServletUtils.getHttpServletRequest();
        String token = httpServletRequest.getHeader(AUTHORIZATION);
        if (StrUtil.isNotEmpty(token)) {
            if (token.toLowerCase().contains(TOKEN_HEAD)) {
                token = token.substring(TOKEN_HEAD.length());
            }
        }
        return token;
    }


    /**
     * 判断令牌是否过期
     *
     * @param token 令牌
     * @return 是否过期
     */
    public static Boolean isTokenExpired(String token, String secret) {
        try {
            Date tokenExpiredTime = getTokenExpiredTime(token, secret);
            return tokenExpiredTime.before(DateUtil.date());
        } catch (Exception e) {
            e.printStackTrace();
            return true;
        }
    }

    public static Date getTokenExpiredTime(String token, String secret) {
        try {
            Claims claims = getClaimsFromToken(token, secret);
            return claims.getExpiration();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取用户名
     *
     * @param token
     * @param secret
     * @return
     */
    public static String getUsernameFromToken(String token, String secret) {
        String username;
        try {
            Claims claims = getClaimsFromToken(token, secret);
            username = claims.getSubject();
        } catch (Exception e) {
            username = null;
        }
        return username;
    }

    /**
     * 从令牌中获取数据声明
     *
     * @param token 令牌
     * @return 数据声明
     */
    public static Claims getClaimsFromToken(String token, String secret) {
        Claims claims;
        try {
            claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
        } catch (Exception e) {
            claims = null;
        }
        return claims;
    }
}
